import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/common/prisma/PrismaService';
import DictQueryParam from '../param/DictQueryParam';
import PageResult from 'src/common/PageResult';
import DictTypeDto from '../dto/DictTypeDto';
import { plainToInstance } from 'class-transformer';
import { Util } from 'src/common/Util';
import ServiceException from 'src/common/ServiceException';
import DictDataDto from '../dto/DictDataDto';
import { CacheUtil } from 'src/common/CacheUtil';
import { CacheKey } from 'src/common/CacheKey';

/*
 * @Author: jingfuu@163.com
 * @Date: 2024-11-26 10:21:24
 * @LastEditTime: 2024-11-26 16:44:15
 * @Description: 字典服务
 */
@Injectable()
class DictService {
  constructor(private prisma: PrismaService) {}

  async list(param: DictQueryParam): Promise<PageResult<DictTypeDto>> {
    const skip = param.pageNum != 0 ? (param.pageNum - 1) * param.pageSize : 0;
    const whereClause: any = this.generateDictTypeQueryCondition(param);
    const [total, dictTypes] = await this.prisma.$transaction([
      this.prisma.sysDictType.count({ where: whereClause }),
      this.prisma.sysDictType.findMany({
        skip,
        take: param.pageSize,
        orderBy: {
          createTime: 'desc',
        },
        where: whereClause,
      }),
    ]);
    const rows: DictTypeDto[] = plainToInstance(DictTypeDto, dictTypes);
    return {
      total,
      rows,
    };
  }

  async findDictTypeList(): Promise<DictTypeDto[]> {
    const sysDictTypes = await this.prisma.sysDictType.findMany();
    return plainToInstance(DictTypeDto, sysDictTypes);
  }
  private generateDictTypeQueryCondition(param: DictQueryParam): any {
    const whereClause: any = {};

    if (param.dictName) {
      whereClause.dictName = {
        contains: param.dictName,
      };
    }

    if (param.dictType !== undefined) {
      whereClause.dictType = param.dictType;
    }

    if (param.status !== undefined) {
      whereClause.status = param.status;
    }
    if (param.params?.beginTime) {
      const beginTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.beginTime}T10:00:00`),
      );
      if (!isNaN(beginTime.getTime())) {
        // Check if the date is valid
        whereClause.createTime = {
          ...whereClause.createTime,
          gte: beginTime,
        };
      }
    }
    if (param.params?.endTime) {
      const endTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.endTime}T23:59:59`),
      );
      if (!isNaN(endTime.getTime())) {
        // Check if the date is valid
        whereClause.createTime = {
          ...whereClause.createTime,
          lte: endTime,
        };
      }
    }
    return whereClause;
  }

  async deleteDictType(id: number) {
    const dictType = await this.prisma.sysDictType.findUnique({
      where: { dictId: id },
    });
    if (!dictType) return;
    await this.prisma.sysDictType.delete({ where: { dictId: id } });
    CacheUtil.delCache(CacheKey.SYSTEM_DICT + dictType.dictType);
  }

  async findDictTypeDetail(id: number): Promise<DictTypeDto> {
    const sysDictType = await this.prisma.sysDictType.findUnique({
      where: { dictId: id },
    });
    return plainToInstance(DictTypeDto, sysDictType);
  }

  async createDictType(dict: DictTypeDto) {
    await this.checkDictType(dict.dictType, null);
    await this.prisma.sysDictType.create({
      data: {
        dictName: dict.dictName,
        dictType: dict.dictType,
        status: dict.status,
        remark: dict.remark,
      },
    });
    CacheUtil.delCache(CacheKey.SYSTEM_DICT + dict.dictType);
  }
  async updateDictType(dict: DictTypeDto) {
    await this.checkDictType(dict.dictType, dict.dictId);
    await this.prisma.sysDictType.update({
      data: {
        dictName: dict.dictName,
        dictType: dict.dictType,
        remark: dict.remark,
        status: dict.status,
      },
      where: { dictId: dict.dictId },
    });
    CacheUtil.delCache(CacheKey.SYSTEM_DICT + dict.dictType);
  }

  private async checkDictType(dictType: string, dictId: number) {
    const sysDictType = await this.prisma.sysDictType.findFirst({
      where: { dictType: dictType },
    });
    if (!dictId) {
      if (sysDictType) {
        throw new ServiceException('字典类型' + dictType + '重复');
      }
    } else {
      if (sysDictType && sysDictType.dictId != dictId) {
        throw new ServiceException('字典类型' + dictType + '重复');
      }
    }
  }

  async exportDictType(param: DictQueryParam) {
    const whereClause: any = this.generateDictTypeQueryCondition(param);
    const sysDictTypes = await this.prisma.sysDictType.findMany({
      orderBy: {
        createTime: 'desc',
      },
      where: whereClause,
    });
    const dictTypeDtos = plainToInstance(DictTypeDto, sysDictTypes);
    // 设置列头
    const header = [
      { header: '字典主键', key: 'id', width: 10 },
      { header: '字典名称', key: 'dictName', width: 20 },
      { header: '字典类型', key: 'dictType', width: 20 },
      { header: '状态', key: 'status', width: 20 },
    ];
    const dictTypes = dictTypeDtos.map((dictType) => {
      return {
        id: dictType.dictId,
        dictName: dictType.dictName,
        dictType: dictType.dictType,
        status: dictType.status == '0' ? '正常' : '停用',
      };
    });
    return Util.excelExport(dictTypes, header);
  }

  async refreshCache() {
    await CacheUtil.deleteKeysWithPrefix(CacheKey.SYSTEM_DICT);
  }

  async listData(param: DictQueryParam): Promise<PageResult<DictDataDto>> {
    const skip = param.pageNum != 0 ? (param.pageNum - 1) * param.pageSize : 0;
    const whereClause: any = this.generateDictDataQueryCondition(param);
    const [total, dictDatas] = await this.prisma.$transaction([
      this.prisma.sysDictData.count({ where: whereClause }),
      this.prisma.sysDictData.findMany({
        skip,
        take: param.pageSize,
        orderBy: {
          dictSort: 'asc',
        },
        where: whereClause,
      }),
    ]);
    const rows: DictDataDto[] = plainToInstance(DictDataDto, dictDatas);
    return {
      total,
      rows,
    };
  }
  private generateDictDataQueryCondition(param: DictQueryParam): any {
    const whereClause: any = {};
    if (param.dictType !== undefined) {
      whereClause.dictType = param.dictType;
    }
    if (param.dictLabel !== undefined) {
      whereClause.dictLabel = param.dictLabel;
    }
    if (param.status !== undefined) {
      whereClause.status = param.status;
    }
    return whereClause;
  }

  async findDictDataByType(dictType: string) {
    let dictDataDto = await CacheUtil.getCacheObject<DictDataDto[]>(
      CacheKey.SYSTEM_DICT + dictType,
    );
    if (dictDataDto) return dictDataDto;
    // 查询出字典类型
    const sysDictType = await this.prisma.sysDictType.findFirst({
      where: {
        dictType,
      },
    });
    const dictTypeDto = plainToInstance(DictTypeDto, sysDictType);
    if (!dictTypeDto) {
      throw new ServiceException('字典类型不存在');
    }
    if (dictTypeDto.status === '1') {
      throw new ServiceException('字典类型已停用');
    }
    // 查询出字段数据
    const sysDictData = await this.prisma.sysDictData.findMany({
      where: {
        dictType,
        status: '0',
      },
      orderBy: {
        dictType: 'asc',
      },
    });
    dictDataDto = plainToInstance(DictDataDto, sysDictData);
    if (!dictDataDto) {
      throw new ServiceException('字典不存在');
    }
    CacheUtil.setCacheObject(
      CacheKey.SYSTEM_DICT + dictType,
      dictDataDto,
      3600 * 2,
    );
    return dictDataDto;
  }

  async deleteDictData(id: number) {
    const dictData = await this.prisma.sysDictData.findUnique({
      where: {
        dictCode: id,
      },
    });
    if (!dictData) return;
    await this.prisma.sysDictData.delete({
      where: {
        dictCode: id,
      },
    });
    CacheUtil.delCache(CacheKey.SYSTEM_DICT + dictData.dictType);
  }

  async findDictDataById(id: number): Promise<DictDataDto> {
    const sysDictData = await this.prisma.sysDictData.findUnique({
      where: {
        dictCode: id,
      },
    });
    return plainToInstance(DictDataDto, sysDictData);
  }

  async updateDictData(dict: DictDataDto) {
    await this.checkDictLabel(dict.dictLabel, dict.dictCode);
    await this.prisma.sysDictData.update({
      where: {
        dictCode: dict.dictCode,
      },
      data: {
        dictSort: dict.dictSort,
        dictLabel: dict.dictLabel,
        dictValue: dict.dictValue,
        dictType: dict.dictType,
        cssClass: dict.cssClass,
        listClass: dict.listClass,
        isDefault: dict.isDefault,
      },
    });
    CacheUtil.delCache(CacheKey.SYSTEM_DICT + dict.dictType);
  }
  async createDictData(dict: DictDataDto) {
    await this.checkDictLabel(dict.dictLabel, null);
    await this.prisma.sysDictData.create({
      data: {
        dictSort: dict.dictSort,
        dictLabel: dict.dictLabel,
        dictValue: dict.dictValue,
        dictType: dict.dictType,
        cssClass: dict.cssClass,
        listClass: dict.listClass,
        isDefault: dict.isDefault,
        status: dict.status,
        remark: dict.remark,
      },
    });
    CacheUtil.delCache(CacheKey.SYSTEM_DICT + dict.dictType);
  }

  private async checkDictLabel(dictLabel: string, dictId: number) {
    const dictData = await this.prisma.sysDictData.findFirst({
      where: { dictLabel: dictLabel },
    });
    if (!dictId) {
      if (dictData) {
        throw new ServiceException('字典标签' + dictLabel + '重复');
      }
    } else {
      if (dictData && dictData.dictCode != dictId) {
        throw new ServiceException('字典标签' + dictLabel + '重复');
      }
    }
  }

  async exportDictData(param: DictQueryParam) {
    const whereClause: any = this.generateDictDataQueryCondition(param);
    const sysDictDatas = await this.prisma.sysDictData.findMany({
      orderBy: {
        createTime: 'desc',
      },
      where: whereClause,
    });
    const sysDictDataDtos = plainToInstance(DictDataDto, sysDictDatas);
    // 设置列头
    const header = [
      { header: '字典编码', key: 'id', width: 10 },
      { header: '字典排序', key: 'dictSort', width: 20 },
      { header: '字典标签', key: 'dictLabel', width: 20 },
      { header: '字典键值', key: 'dictValue', width: 20 },
      { header: '字典类型', key: 'dictType', width: 20 },
      { header: '是否默认', key: 'isDefault', width: 20 },
      { header: '状态', key: 'status', width: 20 },
    ];
    const dictDatas = sysDictDataDtos.map((dictData) => {
      return {
        id: dictData.dictCode,
        dictSort: dictData.dictSort,
        dictLabel: dictData.dictLabel,
        dictValue: dictData.dictValue,
        dictType: dictData.dictType,
        isDefault: dictData.isDefault == '0' ? '是' : '否',
        status: dictData.status == '0' ? '正常' : '停用',
      };
    });
    return Util.excelExport(dictDatas, header);
  }
}
export default DictService;
